﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

public class GoalTrigger : ViewableObject
{
    private List<Expected> m_expecting;
    private bool m_objectIsTeleporting;
    // Flag used in a hackish way to allow us to call the HUD _after_ LevelBase has been transitioned to
    private bool m_needsInit;
    private bool m_removeObject;

    protected new GoalTrigger.Type thisType;
     /**
     * creates a CollidableObject at 'placement' of type 'type'.
     * initializes origin, and
     * type. This will set the SpawnPointer for this instance
     * to null.
     * @param type an instance of ObjectFactory.TypeEnum which
     * specifies what type of CollidableObject to create
     * @param placement the world x,y,z coordinates that define
     * where this instance is placed.
     * @see ObjectFactory.TypeEnum
     */
    public GoalTrigger(GoalTrigger.Type type, Vector3 placement)
        : base(type, placement)
    {
        thisType = type;
        m_expecting = new List<Expected>();
        m_needsInit = true;
        m_removeObject = false;
    }

    /**
     * sets an object to be recognized as recieved as a goal
     * object. sets the number of this object to expect to 1.
     */
    public void addGoal(MissionObject.Type type)
    {
        addGoal(type, 1);
    }

    /**
     * sets an object to be recognized as recieved as a goal
     * object. num is the number of this object that are
     * expected before that object is no longer a goal object.
     */
    public void addGoal(MissionObject.Type type, int num)
    {
        removeGoal(type);
        if (num > 0)
        {
            m_expecting.Add(new Expected(type, num));
        }
    }

    /**
     * removes the specified type from the list of expected
     * goal objects regardless of how many objects are left.
     */
    public void removeGoal(MissionObject.Type type)
    {
        m_expecting.RemoveAll(e => e.type == type);
    }

    /**
     * returns the remaining number of the specified object 
     * this GoalTrigger is m_expecting.
     * @param type the type of object to query about
     * @return the number of the queried object this 
     * GoalTrigger is m_expecting. reurns 0 if it is not
     * m_expecting the specified object at all.
     */
    public int getGoal(MissionObject.Type type)
    {
        foreach (Expected e in m_expecting)
        {
            if (e.type == type)
            {
                return e.amount;
            }
        }
        return 0;
    }

    /**
     * Check whether we actually have something to report here.
     */
    public bool isEmpty()
    {
        if (m_expecting.Count == 0)
        {
            return true;
        }
        return false;
    }

    /**
     * Our child teleporter will kindly inform us that it is done with
     * its teleport animation.
     */
    public void informTeleportFinished()
    {
        m_objectIsTeleporting = false;
    }

    /**
     * Calls the HUD and displays relevant quest information.
     */
    private void displayToHUD()
    {
        LevelBase level = ((LevelBase)Game.getGame().getEnvStack().currentEnv());
        level.getHUD().setMinimapMessage(
            "Find: " + m_expecting[0].type.myType, m_expecting[0].amount);
        level.getHUD().setNoticeMessage(
            "Go find " + m_expecting[0].amount + " " + m_expecting[0].type.myType + "(s)", 4000);
    }

    /**
     * Sends the HUD necessary information for displaying minimap markers.
     */
    private void refreshObjectPositions()
    {
        LevelBase level = ((LevelBase)Game.getGame().getEnvStack().currentEnv());
        level.getHUD().setMissionObjectPositions(level.getPositionsFor(m_expecting[0].type.myType));
    }

    public override void update(double elapsed)
    {
        if (m_needsInit)
        {
            // We're displaying our quest info to the HUD now because LevelBase is not the current
            // environment when in our constructor. 
            m_needsInit = false;
            // Display our first quest
            displayToHUD();
        }
        refreshObjectPositions();

        if (m_removeObject && !m_objectIsTeleporting)
        {
            // Wait for the teleporting sequence to finish before setting our next quest
            removeGoal(m_expecting[0].type);
            // Update HUD with our new Goal
            if (m_expecting.Count > 0)
            {
                displayToHUD();
            }
            m_removeObject = false;
        }

        //dont call base.update b/c i dont want to be culled
        //so i can remember the goal items
        currentAnimation.update(elapsed);
        screenCoord = Camera.worldToScreen(origin);

        List<CollidableObject> colliding = LevelBase.collidesWith(this);
        //see if objects that are in the goal are registered
        //as goal objects. decrement amounts as needed.
        //if they are decremented to 0 then remove them from the
        //list
        foreach (CollidableObject co in colliding)
        {
            if (co is MissionObject && !((MissionObject)co).isBeingUsed)
            {
                // Make sure we're actually expecting something before checking for it
                if (m_expecting.Count > 0)
                {
                    Expected e = m_expecting[0];
                    if (e.type == co.myType)
                    {
                        if (e.amount <= 1)
                        {
                            m_removeObject = true;
                        }
                        else
                        
                        --e.amount;
                    }
                    // Increment the HUD
                    ((LevelBase)Game.getGame().getEnvStack().currentEnv()).getHUD().incrementFound();
                    TeleportObject tele = new TeleportObject(TeleportObject.Type.Teleport, co.position); 
                    Game.getGame().getSoundManager().playOneSoundEffect(((AudioAsset)Game.getGame().getAssetLibrary().getAudio(AssetLibrary.audioType.SOUND_EFFECT).get("transporter")).sound, 1.0f);
                    tele.setTeleporting((MissionObject)co);
                    tele.setParentTrigger(this);
                    ((MissionObject)co).setSuccess();
                    m_objectIsTeleporting = true;
                    LevelBase.addObject(tele);
                }
            }
        }
    }

    class Expected
    {
        public readonly MissionObject.Type type;
        public int amount = 1;

        public Expected(MissionObject.Type t, int num)
        {
            type = t;
            amount = num;
        }
    }

    public new class Type : ViewableObject.Type
    {
        //triggers
        public static readonly Type LoadingZone = new Type(
            ObjectFactory.TypeEnum.LoadingZone,//type
            new Vector3(150, 0, 0),//origin
            new Vector3(300, 1, 800),//collision
            new ArrayList { 
                new Frame(
                    Game.getGame().getAssetLibrary().get(AssetLibrary.assetType.LOADING_DOCK).get("loading dock"), 
                    new Rectangle(0, 0, 300, 400), 
                    0, 
                    new Vector2(150, 400)) });//frameList

        //actual class data

        /**
         * this is a dummy constructor.
         */
        protected Type() { }

        /**
         * Private constructor.
         * This private constructor ensures that only 
         * the pre-specified Type objects can be used 
         * and compared against.
         * @param origin
         * @param collision
         * @param basic
         * @param destruction
         */
        protected Type(Vector3 origin, Vector3 collision)
        {
        }

        protected Type(ObjectFactory.TypeEnum type, Vector3 origin, Vector3 collision,
            ArrayList stasisFrames)
            : base(type, origin, collision, true, stasisFrames, "loadingzone", 0, true)
        {
        }

        public static new GoalTrigger.Type getType(ObjectFactory.TypeEnum type)
        {
            switch (type)
            {
                case ObjectFactory.TypeEnum.LoadingZone: return LoadingZone;
            }
            return null;
        }
    }
}
